import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.StringTokenizer;

public class RO_ConvertUSERtoITEM {
	static User[] USER = RO_ReadASCII.USER;
	static Item[] ITEM = new Item[624961];
	static String SER_PATH = RO_ReadASCII.FILE_PATH + ".ser";
	static String FILE_PATH_GENRE="../track1/genreData1.txt";
	static String FILE_PATH_ARTIST="../track1/artistData1.txt";
	static String FILE_PATH_ALBUM="../track1/albumData1.txt";
	static String FILE_PATH_TRACK="../track1/trackData1.txt";
	
	static String SUFFIX = "";
	static boolean TAXONOMY = true;

	public static void go() {
		try {
			createItemArrays();
			sortITEM();
			
			if(TAXONOMY){
				System.out.println("Read genre...");
				readGenre();
				System.out.println("Read artist...");
				readArtist();
				System.out.println("Read album...");
				readAlbum();
				System.out.println("Read track...");
				readTrack();
				shrinkAlbumArtist();
			}
			
			writeSerialisedResult(SER_PATH + ".item" + SUFFIX, ITEM);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private static void createItemArrays() {
		System.out.println("createItemArrays: " + USER[0]);
		long time = System.currentTimeMillis();

		initItemArray();

		for (int userID = 0; userID < USER.length; userID++) {
			User user = USER[userID];

			for (int v = 0; v < user.ilen; v++) {
				int itemID = user.items[v];
				byte vote = user.votes[v];
				ITEM[itemID].put(userID, vote);
				ITEM[itemID].mean += (double) vote;
			}
		}

		shrinkItems();
		System.out.println(System.currentTimeMillis() - time);
	}

	private static void initItemArray() {
		for (int i = 0; i < ITEM.length; i++) {
			ITEM[i] = new Item();
		}
	}

	private static void shrinkItems() {
		for (int i = 0; i < ITEM.length; i++) {
			ITEM[i].shrink();
		}
	}
	
	private static void shrinkAlbumArtist() {
		for (int i = 0; i < ITEM.length; i++) {
			if(ITEM[i].getClass() == Album.class){
				((Album)ITEM[i]).shrinkTracks();
			}
			if(ITEM[i].getClass() == Artist.class){
				((Artist)ITEM[i]).shrinkItemBy();
			}
		}
	}

	private static void sortITEM() {
		System.out.println("sortITEM: " + USER[0]);
		long time = System.currentTimeMillis();

		for (Item item : ITEM) {
			item.sort();
			item.mean = item.mean / item.ulen;
		}

		System.out.println(System.currentTimeMillis() - time);
	}
	
	private static void readGenre() throws Exception {
		File file = new File(FILE_PATH_GENRE);
		BufferedReader bufRdr = new BufferedReader(new FileReader(file));
		String line = null;
		int genreID = -1;		

		while ((line = bufRdr.readLine()) != null) {
			genreID = Integer.valueOf(line);
			ITEM[genreID] = new Genre(ITEM[genreID]);
		}
		bufRdr.close();
	}
	
	private static void readArtist() throws Exception {
		File file = new File(FILE_PATH_ARTIST);
		BufferedReader bufRdr = new BufferedReader(new FileReader(file));
		String line = null;
		int artistID = -1;		

		while ((line = bufRdr.readLine()) != null) {
			artistID = Integer.valueOf(line);
			ITEM[artistID] = new Artist(ITEM[artistID]);
		}
		bufRdr.close();
	}
	
	private static void readAlbum() throws Exception {
		File file = new File(FILE_PATH_ALBUM);
		BufferedReader bufRdr = new BufferedReader(new FileReader(file));
		String line = null;
		StringTokenizer st;
		int albumID = -1;
		int artistID = -1;
		Album album;
		Artist artist;

		while ((line = bufRdr.readLine()) != null) {
			st = new StringTokenizer(line, "|");
			albumID = Integer.valueOf(st.nextToken());
			artistID = parse(st.nextToken());
			album = new Album(ITEM[albumID]);
			
			//Add Artist
			if(artistID >= 0){
				artist = (Artist)ITEM[artistID];
				artist.putItemBy(album); //Add this album to the artist
				album.artist = artist;
			} else {
				album.artist =null;
			}
			ITEM[albumID] = album;
		}
		bufRdr.close();
	}
	
	private static void readTrack() throws Exception {
		File file = new File(FILE_PATH_TRACK);
		BufferedReader bufRdr = new BufferedReader(new FileReader(file));
		String line = null;
		StringTokenizer st;
		int trackID = -1;
		int albumID = -1;
		int artistID = -1;
		
		Track track;


		while ((line = bufRdr.readLine()) != null) {
			st = new StringTokenizer(line, "|");
			trackID = Integer.valueOf(st.nextToken());
			albumID = parse(st.nextToken());
			artistID = parse(st.nextToken());
			track = new Track(ITEM[trackID]);
			
			//Add Album
			if(albumID >= 0){
				((Album)ITEM[albumID]).putTrack(track); //Add this track to the album
				track.album = (Album)ITEM[albumID];
			}	else {
				track.album =null;
			}
			
			//Add Artist
			if(artistID >= 0){
				((Artist)ITEM[artistID]).putItemBy(track); //Add this track to the artist
				track.artist = (Artist)ITEM[artistID];
			} else {
				track.artist =null;
			}
			
			ITEM[trackID] = track;
		}
		bufRdr.close();
	}
	
	private static int parse(String str){
		if(str.equals("None")){
			return -1;
		} else {
			return Integer.parseInt(str);
		}
	}

	private static void writeSerialisedResult(String outputFile, Serializable object) {
		System.out.println("writeSerialisedResult: " + outputFile);
		long time = System.currentTimeMillis();

		try {
			OutputStream file = new FileOutputStream(outputFile);
			OutputStream buffer = new BufferedOutputStream(file);
			ObjectOutput output = new ObjectOutputStream(buffer);
			try {
				output.writeObject(object);
			} finally {
				output.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println(System.currentTimeMillis() - time);
	}
}
